package com.dateConstruction._04_arithExpression;

// 算术表达式（整数、不包括位运算）
/*

这次不转后缀了，而是递归思路
首先需要明确好这些概念，算术表达式的BNF语法定义：
<算术表达式> ::= <项> | <项> <加减运算符> 项
<乘除运算符> ::= * | / | %
<项> ::= <因子> | <因子> <乘除运算符> <因子>
<因子> ::= <常数> | (<算术表达式>)
我们的思路就是拿到<算术表达式>之后，找到它的<项>，计算每一个<项>，要计算<项>就得再计算每个<因子>，
因此，我们只要计算好了每个<因子>，进而计算好每个<项>，进而就能计算出这个<算术表达式>了
我们依然以1+2*(3-4)+56为例
我们能找到它的项是1，2*(3-4)，56
1和56都是常数项不用算，2*(3-4)则是一个因子，其中2是一个常数因子不用算，(3-4)则是一个算术表达式因子，其中项为3和4，都是常数项
这是我们人脑算的拆解过程，但是机器怎么能精准定位每一项、每一个因子呢？
我们可以观察到，加减运算符只出现在算术表达式中，而且它作为项与项之间唯一的分隔符，因此我们可以通过它才找到每一项，
当然其中还有一个特殊的存在："(", ")"，括号中的加减运算符属于下一级算术表达式的加减运算符
而项中乘除运算符则是因子和因子之间的分隔符


 */
public class ArithmeticExpression {
    
    // 中缀算术表达式字符串
    private String infix;
    // 当前字符序号
    private int index;
    
    // 构造方法，infix指定中缀表达式
    public ArithmeticExpression(String infix) {
        this.infix = infix;
        this.index = 0;
    }
    
    // 计算从index开始的一个（子）算术表达式，返回整数值，其中进行多<项>加减运算
    public int intValue() {
        // 计算第一项的值
        int value1 = term();
        while (this.index < this.infix.length()) {
            char op = infix.charAt(this.index);
            if (op == '+' || op == '-') {
                this.index++;
                int value2 = term();
                if (op == '+') {
                    value1 += value2;
                } else if (op == '-') {
                    value1 -= value2;
                }
            } else {
                // 遇到')'，结束循环
                break;
            }
        }
        return value1;
    }
    
    // 计算从index开始的一<项>，其中进行多<因子>的乘除运算
    private int term() {
        // TODO Auto-generated method stub
        int value1 = factor();
        while (this.index < this.infix.length()) {
            char op = this.infix.charAt(index);
            if (op == '*' || op == '/' || op == '%') {
                this.index++;
                int value2 = factor();
                if (op == '*') {
                    value1 *= value2;
                } else if (op == '/') {
                    value1 /= value2;
                } else if (op == '%') {
                    value1 %= value2;
                }
            } else {
                break;
            }
        }
        return value1;
    }

    // 计算从index开始的一个<因子>，其中包括以()为界的子表达式
    private int factor() {
        // TODO Auto-generated method stub
        if (this.infix.charAt(index) == '(') {
            // 跳过'('
            this.index++;
            int value = intValue();
            // 跳过')'
            this.index++;
            return value;
        }
        return constant();
    }

    private int constant() {
        // TODO Auto-generated method stub
        if (this.index < this.infix.length()) {
            int sign = 1;
            int value = 0;
            char op = this.infix.charAt(index);
            if (op == '-') {
                sign = -1;
                this.index++;
            } else if (op == '+') {
                this.index++;
            }
            while (this.index < this.infix.length()) {
                char ch = this.infix.charAt(index);
                
                if (ch >= '0' && ch <= '9') {
                    this.index++;
                    value = value * 10 + ch - '0';
                } else {
                    break;
                }
            }
            return value * sign;
        }
        throw new NumberFormatException("\"" + infix.substring(index - 1) + "\"不能转换成整数");
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ArithmeticExpression ae = new ArithmeticExpression("1+2*(3-4)+56");
        System.out.println(ae.intValue());
    }

}
